#include <sdk.h>
#include "debuggeroptionsdlg.h"
#include "Debugger.h"

class DebuggerConfigurationPanel : public wxPanel {
  public:
    void ValidateExecutablePath() {
      wxTextCtrl *pathCtrl = XRCCTRL( *this, "txtExecutablePath", wxTextCtrl );
      wxString path = pathCtrl->GetValue();
      Manager::Get()->GetMacrosManager()->ReplaceEnvVars( path );
      if( !wxFileExists( path ) ) {
        pathCtrl->SetForegroundColour( *wxWHITE );
        pathCtrl->SetBackgroundColour( *wxRED );
        pathCtrl->SetToolTip( _T( "Full path to the debugger's executable. Executable can't be found on the filesystem!" ) );
      } else {
        pathCtrl->SetForegroundColour( wxNullColour );
        pathCtrl->SetBackgroundColour( wxNullColour );
        pathCtrl->SetToolTip( _T( "Full path to the debugger's executable." ) );
      }
      pathCtrl->Refresh();
    }
  private:
    void OnBrowse( M_Code_unused wxCommandEvent &event ) {
      wxString oldPath = XRCCTRL( *this, "txtExecutablePath", wxTextCtrl )->GetValue();
      Manager::Get()->GetMacrosManager()->ReplaceEnvVars( oldPath );
      wxFileDialog dlg( this, _T( "Select executable file" ), wxEmptyString, oldPath,
                        wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
      PlaceWindow( &dlg );
      if( dlg.ShowModal() == wxID_OK ) {
        wxString newPath = dlg.GetPath();
        XRCCTRL( *this, "txtExecutablePath", wxTextCtrl )->ChangeValue( newPath );
      }
    }

    void OnTextChange( M_Code_unused wxCommandEvent &event ) {
      ValidateExecutablePath();
    }
  private:
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE( DebuggerConfigurationPanel, wxPanel )
  EVT_BUTTON( XRCID( "btnBrowse" ), DebuggerConfigurationPanel::OnBrowse )
  EVT_TEXT( XRCID( "txtExecutablePath" ), DebuggerConfigurationPanel::OnTextChange )
END_EVENT_TABLE()

DebuggerConfiguration::DebuggerConfiguration( const ConfigManagerWrapper &config ) : cbDebuggerConfiguration( config ) {
}

cbDebuggerConfiguration* DebuggerConfiguration::Clone() const {
  return new DebuggerConfiguration( *this );
}

wxPanel* DebuggerConfiguration::MakePanel( wxWindow *parent ) {
  DebuggerConfigurationPanel *panel = new DebuggerConfigurationPanel;
  wxXmlResource* xml_res = wxXmlResource::Get();
  wxString resPath = ConfigManager::GetDataFolder() + _T( "/配置调试器.xrc" );
  xml_res->Load( resPath );
  if( !xml_res->LoadPanel( panel, parent, _T( "dlgDebuggerOptions" ) ) ) {
    return panel;
  }
  XRCCTRL( *panel, "txtExecutablePath", wxTextCtrl )->ChangeValue( GetDebuggerExecutable( false ) );
  panel->ValidateExecutablePath();
  XRCCTRL( *panel, "chkDisableInit", wxCheckBox )->SetValue( GetFlag( DisableInit ) );
  XRCCTRL( *panel, "txtArguments", wxTextCtrl )->ChangeValue( GetUserArguments( false ) );
  XRCCTRL( *panel, "rbType", wxRadioBox )->SetSelection( IsGDB() ? 0 : 1 );
  XRCCTRL( *panel, "txtInit", wxTextCtrl )->ChangeValue( GetInitCommands() );
  XRCCTRL( *panel, "txtInit", wxTextCtrl )->SetMinSize( wxSize( -1, 75 ) );;
  XRCCTRL( *panel, "chkWatchArgs", wxCheckBox )->SetValue( GetFlag( WatchFuncArgs ) );
  XRCCTRL( *panel, "chkWatchLocals", wxCheckBox )->SetValue( GetFlag( WatchLocals ) );
  XRCCTRL( *panel, "chkCatchExceptions", wxCheckBox )->SetValue( GetFlag( CatchExceptions ) );
  XRCCTRL( *panel, "chkTooltipEval", wxCheckBox )->SetValue( GetFlag( EvalExpression ) );
  XRCCTRL( *panel, "chkAddForeignDirs", wxCheckBox )->SetValue( GetFlag( AddOtherProjectDirs ) );
  XRCCTRL( *panel, "chkDoNotRun", wxCheckBox )->SetValue( GetFlag( DoNotRun ) );
  XRCCTRL( *panel, "choDisassemblyFlavor", wxChoice )->SetSelection( m_config.ReadInt( _T( "disassembly_flavor" ), 0 ) );
  XRCCTRL( *panel, "txtInstructionSet", wxTextCtrl )->ChangeValue( m_config.Read( _T( "instruction_set" ), wxEmptyString ) );
  return panel;
}

bool DebuggerConfiguration::SaveChanges( wxPanel *panel ) {
  m_config.Write( _T( "executable_path" ), XRCCTRL( *panel, "txtExecutablePath", wxTextCtrl )->GetValue() );
  m_config.Write( _T( "disable_init" ), XRCCTRL( *panel, "chkDisableInit", wxCheckBox )->GetValue() );
  m_config.Write( _T( "user_arguments" ), XRCCTRL( *panel, "txtArguments", wxTextCtrl )->GetValue() );
  m_config.Write( _T( "type" ), XRCCTRL( *panel, "rbType", wxRadioBox )->GetSelection() );
  m_config.Write( _T( "init_commands" ), XRCCTRL( *panel, "txtInit", wxTextCtrl )->GetValue() );
  m_config.Write( _T( "watch_args" ), XRCCTRL( *panel, "chkWatchArgs", wxCheckBox )->GetValue() );
  m_config.Write( _T( "watch_locals" ), XRCCTRL( *panel, "chkWatchLocals", wxCheckBox )->GetValue() );
  m_config.Write( _T( "catch_exceptions" ), XRCCTRL( *panel, "chkCatchExceptions", wxCheckBox )->GetValue() );
  m_config.Write( _T( "eval_tooltip" ), XRCCTRL( *panel, "chkTooltipEval", wxCheckBox )->GetValue() );
  m_config.Write( _T( "add_other_search_dirs" ), XRCCTRL( *panel, "chkAddForeignDirs", wxCheckBox )->GetValue() );
  m_config.Write( _T( "do_not_run" ), XRCCTRL( *panel, "chkDoNotRun", wxCheckBox )->GetValue() );
  m_config.Write( _T( "disassembly_flavor" ), XRCCTRL( *panel, "choDisassemblyFlavor", wxChoice )->GetSelection() );
  m_config.Write( _T( "instruction_set" ), XRCCTRL( *panel, "txtInstructionSet", wxTextCtrl )->GetValue() );
  return true;
}

bool DebuggerConfiguration::GetFlag( Flags flag ) {
  switch( flag ) {
    case DisableInit:
      return m_config.ReadBool( _T( "disable_init" ), true );
    case WatchFuncArgs:
      return m_config.ReadBool( _T( "watch_args" ), true );
    case WatchLocals:
      return m_config.ReadBool( _T( "watch_locals" ), true );
    case CatchExceptions:
      return m_config.ReadBool( _T( "catch_exceptions" ), true );
    case EvalExpression:
      return m_config.ReadBool( _T( "eval_tooltip" ), false );
    case AddOtherProjectDirs:
      return m_config.ReadBool( _T( "add_other_search_dirs" ), false );
    case DoNotRun:
      return m_config.ReadBool( _T( "do_not_run" ), false );
    default:
      return false;
  }
}

void DebuggerConfiguration::SetFlag( Flags flag, bool value ) {
  switch( flag ) {
    case DisableInit:
      m_config.Write( _T( "disable_init" ), value );
      break;
    case WatchFuncArgs:
      m_config.Write( _T( "watch_args" ), value );
      break;
    case WatchLocals:
      m_config.Write( _T( "watch_locals" ), value );
      break;
    case CatchExceptions:
      m_config.Write( _T( "catch_exceptions" ), value );
      break;
    case EvalExpression:
      m_config.Write( _T( "eval_tooltip" ), value );
      break;
    case AddOtherProjectDirs:
      m_config.Write( _T( "add_other_search_dirs" ), value );
      break;
    case DoNotRun:
      m_config.Write( _T( "do_not_run" ), value );
      break;
    default:
      ;
  }
}

bool DebuggerConfiguration::IsGDB() {
  return m_config.ReadInt( _T( "type" ), 0 ) == 0;
}

wxString DebuggerConfiguration::GetDebuggerExecutable( bool expandMacro ) {
  wxString result = m_config.Read( _T( "executable_path" ), wxEmptyString );
  if( expandMacro ) {
    Manager::Get()->GetMacrosManager()->ReplaceEnvVars( result );
  }
  return !result.empty() ? result : cbDetectDebuggerExecutable( _T( "gdb" ) );
}

wxString DebuggerConfiguration::GetUserArguments( bool expandMacro ) {
  wxString result = m_config.Read( _T( "user_arguments" ), wxEmptyString );
  if( expandMacro ) {
    Manager::Get()->GetMacrosManager()->ReplaceEnvVars( result );
  }
  return result;
}

wxString DebuggerConfiguration::GetDisassemblyFlavorCommand() {
  int disassembly_flavour = m_config.ReadInt( _T( "disassembly_flavor" ), 0 );
  wxString flavour = _T( "set disassembly-flavor " );
  switch( disassembly_flavour ) {
    case 1: {
      flavour << _T( "att" );
      break;
    }
    case 2: {
      flavour << _T( "intel" );
      break;
    }
    case 3: {
      wxString instruction_set = m_config.Read( _T( "instruction_set" ), wxEmptyString );
      flavour << instruction_set;
      break;
    }
    default:
      flavour << _T( "intel" );
  }
  return flavour;
}

wxString DebuggerConfiguration::GetInitCommands() {
  return m_config.Read( _T( "init_commands" ), wxEmptyString );
}
